/*
 * File: FileUtil.java
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package tvseries.utils;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.log4j.Logger;

import tvseries.beans.EpisodeBean;
import tvseries.beans.SeriesBean;
import tvseries.entity.Episode;
import tvseries.entity.Series;

/**
 * Utility class for managing file based functionality.
 * 
 * @author nish.naidoo@gmail.com
 * 
 */
public class FileUtil
{
	private static final Logger log = Logger.getLogger(FileUtil.class);

	public static void main(String[] args)
	{
		scanAndRename();
	}

	public static boolean exists(EpisodeBean episode)
	{
		SeriesBean series = episode.getSeriesBean();
		if (log.isDebugEnabled())
		{
			if (series == null)
				log.debug("exists: Series is null");
			else
				log.debug("exists: Series id: " + series.getId());
		}

		String seasonNum = (episode.getSeason() < 10) ? "0" + episode.getSeason() : String.valueOf(episode.getSeason());
		String episodeNum = (episode.getEpisode() < 10) ? "0" + episode.getEpisode() : String.valueOf(episode.getEpisode());
		StringBuilder filename = new StringBuilder();
		filename.append(PropUtil.get("filesystem.base"));
		filename.append(File.separatorChar);
		filename.append(series.getTitle());
		filename.append(File.separatorChar);
		filename.append("Season ").append(seasonNum);
		filename.append(File.separatorChar);
		filename.append(series.getTitle());
		filename.append(' ');
		filename.append(seasonNum);
		filename.append('x');
		filename.append(episodeNum);
		filename.append(".avi");

		File f = new File(filename.toString());

		if (log.isDebugEnabled())
			log.debug(f.getAbsolutePath() + ": " + f.exists());
		
		return f.exists();
	}

	public static boolean exists(Series series, Episode episode)
	{
		EpisodeBean e = new EpisodeBean();
		SeriesBean s = new SeriesBean();
		try
		{
			BeanUtils.copyProperties(e, episode);
			BeanUtils.copyProperties(s, series);
			e.setSeriesBean(s);
			return exists(e);
		}
		catch (Exception ex)
		{
			return false;
		}		
	}
	
	public static List<String> scanAndRename()
	{
		List<String> actions = new ArrayList<String>();
		
		String regexSeason = "(\\w+) ?(\\d\\d?)";
		Pattern pS = Pattern.compile(regexSeason);
		String regexEpisode = "[^\\d]+(\\d\\d?)[xXeE]?(\\d\\d).*\\.(.+)";
		Pattern pE = Pattern.compile(regexEpisode);

		File base = new File(PropUtil.get("filesystem.base"));
		actions.add("File system base: " + base.getAbsolutePath());

		File[] series = base.listFiles();
		for (File s : series)
		{
			if (!s.isDirectory())
				continue;

			if (log.isDebugEnabled())
				log.debug("Operating on: " + s.getAbsolutePath());

			actions.add("Checking: " + s.getName());
 
			File[] seasons = s.listFiles();
			for (File season : seasons)
			{
				if (!season.isDirectory())
					continue;

				Matcher mS = pS.matcher(season.getName());
				if (!mS.find())
				{
					if (log.isDebugEnabled())
						log.debug("Unable to identify season: " + season.getAbsolutePath());

					continue;
				}

				String seasonText = mS.group(1);
				String seasonNum = mS.group(2);
				if (seasonNum.length() == 1)
					seasonNum = "0" + seasonNum;

				File newSeason = new File(s.getAbsoluteFile() + String.valueOf(File.separatorChar) + seasonText + " "
						+ seasonNum);
				if (!newSeason.exists())
				{
					if (log.isDebugEnabled())
						log.debug("renaming dir: " + season.getName() + " -> " + newSeason.getName());
					
					actions.add("Renaming directory: [" + season.getName() + "] -> [" + newSeason.getName() + "]");
					
					season.renameTo(newSeason);
					season = newSeason;
				}

				File[] episodes = season.listFiles();
				for (File episode : episodes)
				{
					if (!episode.isFile())
						continue;

					Matcher mE = pE.matcher(episode.getName());
					if (!mE.find())
					{
						log.warn("could not match season/episode/extension (" + mE.groupCount() + "): "
								+ episode.getName());
						continue;
					}

					if (mE.groupCount() != 3)
					{
						log.warn("not enough match groups (" + mE.groupCount() + "): " + episode.getAbsolutePath());
						continue;
					}

					String testSeasonNum = mE.group(1);
					if (testSeasonNum.length() == 1)
						testSeasonNum = "0" + testSeasonNum;

					if (!testSeasonNum.equals(seasonNum))
					{
						log.warn("Season numbers do not match: " + seasonNum + " / " + testSeasonNum);
						continue;
					}

					String episodeNum = mE.group(2);
					String extension = mE.group(3);

					StringBuilder filename = new StringBuilder();
					filename.append(PropUtil.get("filesystem.base"));
					filename.append(File.separatorChar);
					filename.append(s.getName());
					filename.append(File.separatorChar);
					filename.append(season.getName());
					filename.append(File.separatorChar);
					filename.append(s.getName());
					filename.append(' ');
					filename.append(seasonNum);
					filename.append('x');
					filename.append(episodeNum);
					filename.append('.');
					filename.append(extension);

					if (log.isDebugEnabled())
						log.debug("Expected filename: " + filename.toString());

					File newEpisode = new File(filename.toString());
					if (!newEpisode.exists())
					{
						if (log.isDebugEnabled())
							log.debug("renaming file: " + episode.getName() + " -> " + newEpisode.getName());

						actions.add("Renaming file: [" + episode.getName() + "] -> [" + newEpisode.getName() + "]");
						episode.renameTo(newEpisode);
						episode = newEpisode;
						episode.setLastModified(System.currentTimeMillis());
					}
				}
			}
		}
		
		return actions;
	}

	public static void checkStuff()
	{
		File dir = new File(PropUtil.get("filesystem.base"));
		String[] files = dir.list();

		for (String file : files)
		{
			boolean match = file.matches("[^\\d]+(\\d\\d?)[xXeE]?(\\d\\d)[^\\d]+");
			if (match)
				log.info("file: " + file);
		}
	}

	public static void createDemoStructure() throws Exception
	{
		File file = new File("data/files.txt");
		Scanner scanner = new Scanner(file);

		while (scanner.hasNextLine())
		{
			String line = scanner.nextLine();
			File newFile = new File(line);
			if (newFile.getAbsolutePath().endsWith(".avi"))
			{
				String parent = newFile.getParent();
				File parentFile = new File(parent);
				if (!parentFile.exists())
				{
					if (log.isDebugEnabled())
						log.debug("creating parent directory structure: " + parentFile.getAbsolutePath());

					parentFile.mkdirs();
				}

				if (!newFile.exists())
				{
					if (log.isDebugEnabled())
						log.debug("creating new file: " + newFile.getName());

					newFile.createNewFile();
				}
			}
		}
	}
}
